package ssn.common.highchart.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;

import org.apache.commons.beanutils.converters.IntegerArrayConverter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import ssn.common.highchart.service.HighChartService;
import ssn.common.highchart.vo.HighChartVO;
import ssn.common.highchart.vo.PlotLinesVO;
import ssn.common.highchart.vo.SeriesVO;
import ssn.common.vo.WaterConstants;
import egovframework.rte.fdl.string.EgovStringUtil;

@SuppressWarnings({"rawtypes","unchecked"})
public class HighChartServiceImpl implements HighChartService{

	protected Log log = LogFactory.getLog(this.getClass());
	
	/**
	 * flag 1 = waterIOChart(오수 차트), 2 = electChart(전력차트), 4 = waterQualityChart(수질 현황 차트)
	 */
	public Map getChart(List<Map> list, int flag) throws Exception{
		Map resultMap = new LinkedMap();
		if(list == null || list.size() == 0){
			return null;
		}
		switch (flag) {
			case 1:	resultMap.put("waterIOChart", getWaterIOChart(list)); break;
			case 2:	resultMap.put("electChart", getElectChart(list)); break;
			case 3:
				resultMap.put("waterIOChart", getWaterIOChart(list));
				resultMap.put("electChart", getElectChart(list));
				break;
			case 4:	resultMap.put("waterQualityChart", getWaterQualityChartSplit(list)); break;
			case 5:	
				resultMap.put("waterIOChart", getWaterIOChart(list));
				resultMap.put("waterQualityChart", getWaterQualityChart(list));
				break;
			case 6:	
				resultMap.put("electChart", getElectChart(list));
				resultMap.put("waterQualityChart", getWaterQualityChart(list));
				break;
			case 7:	
				resultMap.put("waterIOChart", getWaterIOChart(list));
				resultMap.put("electChart", getElectChart(list));
				resultMap.put("waterQualityChart", getWaterQualityChart(list));
				break;
		}
		return resultMap;
	}
	
	/**
	 * 오수 발생량 차트
	 * @param list
	 * @return
	 * @throws Exception
	 */
	public String getWaterIOChart(List<Map> list) throws Exception{
		HighChartVO hchart = new HighChartVO();
		hchart.getChart().setType("line");
		hchart.getTitle().setText(WaterConstants.IOFLOW_CHART_TITLE);
		hchart.getTitle().setY(10);
		hchart.getSubtitle().setText(WaterConstants.RESOURCE_CHART_TITLE);
		hchart.getSubtitle().setY(30);
		hchart.getxAxis().setCategories(this.getCategories(list));
		hchart.getxAxis().setPlotLines(null);
		hchart.getxAxis().setTitle(null);
		hchart.getyAxis().getTitle().setText(WaterConstants.IOFLOW_CHART_YUNIT);
		hchart.getyAxis().setPlotLines(this.getPlotLines(Integer.parseInt(this.getListLastMapValue(list, "areaCapa")), 3, "#FF0000"));
		hchart.getTooltip().setValuePrefix("");
		hchart.getTooltip().setValueSuffix(WaterConstants.IOFLOW_CHART_YUNIT);
		hchart.getLegend().setAlign(WaterConstants.LEGEND_ALIGN_R);
		hchart.getLegend().setLayout(WaterConstants.LEGEND_LAYOUT_V);
		hchart.getLegend().setVerticalAlign(WaterConstants.LEGEND_V_ALIGN_M);
		hchart.getLegend().setBorderWidth(0);
		hchart.setSeries(this.getSeries(list, WaterConstants.IOFLOW_CHART_NAME_INDEX));
		return getJsonString(hchart);
	}
	
	/**
	 * 전기사용량 차트
	 * @param list
	 * @return
	 * @throws Exception
	 */
	public String getElectChart(List<Map> list) throws Exception{
		HighChartVO hchart = new HighChartVO();
		hchart.getChart().setType("column");
		hchart.getTitle().setText(WaterConstants.ELECT_CHART_TITLE);
		hchart.getTitle().setY(10);
		hchart.getSubtitle().setText(WaterConstants.RESOURCE_CHART_TITLE);
		hchart.getSubtitle().setY(30);
		hchart.getxAxis().setCategories(this.getCategories(list));
		hchart.getxAxis().setPlotLines(null);
		hchart.getxAxis().setTitle(null);
		hchart.getyAxis().getTitle().setText(WaterConstants.ELECT_CHART_YUNIT);
		hchart.getyAxis().setPlotLines(null);
		hchart.getyAxis().setCategories(null);
		hchart.getTooltip().setValuePrefix("");
		hchart.getTooltip().setValueSuffix(WaterConstants.ELECT_CHART_YUNIT);
		hchart.getLegend().setAlign(WaterConstants.LEGEND_ALIGN_C);
		hchart.getLegend().setLayout(WaterConstants.LEGEND_LAYOUT_H);
		hchart.getLegend().setVerticalAlign(WaterConstants.LEGEND_V_ALIGN_B);
		hchart.getLegend().setBorderWidth(1);
		hchart.setSeries(this.getSeries(list, WaterConstants.ELECT_CHART_NAME_INDEX, true));
		return getJsonString(hchart);
	}
	
	
	public String getWaterQualityChart(List<Map> list, boolean legendShow) throws Exception{
		HighChartVO hchart = new HighChartVO();
		hchart.getChart().setType("line");
		hchart.getTitle().setText(this.getListLastMapValue(list, "areaName")+" - "+WaterConstants.QUALITY_CHART_TITLE);
		hchart.getTitle().setY(10);
		hchart.getSubtitle().setText(WaterConstants.RESOURCE_CHART_TITLE);
		hchart.getSubtitle().setY(30);
		hchart.getxAxis().setCategories(this.getCategories(list, WaterConstants.QUALITY_CHART_NAME_INDEX[0]));
		hchart.getxAxis().setPlotLines(null);
		hchart.getxAxis().setTitle(null);
		hchart.getyAxis().getTitle().setText(WaterConstants.QUALITY_CHART_YUNIT);
		hchart.getyAxis().setPlotLines(null);
		hchart.getyAxis().setCategories(null);
		hchart.getTooltip().setValuePrefix("");
		hchart.getTooltip().setValueSuffix(WaterConstants.QUALITY_CHART_YUNIT);
		if(legendShow){
			hchart.getLegend().setAlign(WaterConstants.LEGEND_ALIGN_R);
			hchart.getLegend().setLayout(WaterConstants.LEGEND_LAYOUT_V);
			hchart.getLegend().setVerticalAlign(WaterConstants.LEGEND_V_ALIGN_M);
			hchart.getLegend().setBorderWidth(0);
		}else{
			hchart.getLegend().setEnabled(false);
		}
		hchart.setSeries(this.getSeries(list, WaterConstants.QUALITY_CHART_NAME_INDEX));
		return getJsonString(hchart);
	}
	
	public String getWaterQualityChart(List<Map> list) throws Exception{
		return getWaterQualityChart(list, true);
	}
	
	public Map getWaterQualityChartSplit(List<Map> list) throws Exception{
		Map resultMap = new LinkedMap();
		String[] qualityNameIndex = WaterConstants.QUALITY_CHART_NAME_INDEX;
		for(int i=0; i<qualityNameIndex.length; i++){
			HighChartVO hchart = new HighChartVO();
			hchart.getChart().setType("line");
			hchart.getTitle().setText(WaterConstants.QUALITY_CHART_NAME[i]);
			hchart.getTitle().setY(10);
			hchart.getSubtitle().setText(WaterConstants.RESOURCE_CHART_TITLE);
			hchart.getSubtitle().setY(30);
			hchart.getxAxis().setCategories(this.getCategories(list, qualityNameIndex[i]));
			hchart.getxAxis().setPlotLines(null);
			hchart.getxAxis().setTitle(null);
			hchart.getyAxis().getTitle().setText(WaterConstants.QUALITY_CHART_YUNIT);
			hchart.getyAxis().setPlotLines(this.getPlotLines(WaterConstants.QUALITY_CHART_BASE_LINE[i], 3, "#FF0000"));
			hchart.getyAxis().setMax(WaterConstants.QUALITY_CHART_BASE_LINE[i]*2);
			hchart.getyAxis().setCategories(null);
			hchart.getTooltip().setValuePrefix("");
			hchart.getTooltip().setValueSuffix(WaterConstants.QUALITY_CHART_YUNIT);
			hchart.getLegend().setAlign(WaterConstants.LEGEND_ALIGN_R);
			hchart.getLegend().setLayout(WaterConstants.LEGEND_LAYOUT_V);
			hchart.getLegend().setVerticalAlign(WaterConstants.LEGEND_V_ALIGN_M);
			hchart.getLegend().setBorderWidth(0);
			hchart.setSeries(this.getSeries(list, new String[]{qualityNameIndex[i]}, WaterConstants.QUALITY_CHART_SERIES_CLR[i]));
			resultMap.put(qualityNameIndex[i],  getJsonString(hchart));
		}
		return resultMap;
	}
	
	/**
	 * 기준선 
	 * @param value		: 기준 값
	 * @param width		: 기준선 두께
	 * @param color		: 기준선 색
	 * @return
	 */
	private List getPlotLines(int value, int width, String color){
		List resultList = new ArrayList();
		PlotLinesVO plotVO = new PlotLinesVO();
		plotVO.setValue(value);
		plotVO.setColor(color);
		plotVO.setWidth(width);
		resultList.add(plotVO);
		return resultList;
	}
	
	private List getCategories(List<Map> list){
		return getCategories(list, null);
	}
	
	private List getCategories(List<Map> list, String checkEmptyData){
		List resultList = new ArrayList();
		for(Map vo : list){
			String dailyDate = (String)vo.get("dailyDate");
			if(checkEmptyData != null){
				String tempValue = (String)vo.get(checkEmptyData);
				if(EgovStringUtil.isEmpty(tempValue)){
					tempValue = "0";
				}
				if(!tempValue.equals("0")){
					resultList.add(dailyDate);
				}
			}else{
				resultList.add(dailyDate);
			}
		}
		return resultList;
	}
	
	/**
	 * 차트 리스트 가져오기
	 * @param list
	 * @param index			:상수로 지정한 차트에 대한 이름 인덱스
	 * @param getAreaName : 
	 * @return
	 */
	private List getSeries(List<Map> list, String[] index, String color, boolean getAreaName){
		List resultList = new ArrayList();
		if(getAreaName){
			for(int i=0;i<index.length;i++){
				SeriesVO seriVO = new SeriesVO();
				seriVO.setName(this.getListLastMapValue(list, "areaName"));
				seriVO.setData(this.getSeriesValue(list, index[i]));
				if(EgovStringUtil.isNotEmpty(color))seriVO.setColor(color);
				resultList.add(seriVO);
			}
		}else{
			for(int i=0;i<index.length;i++){
				SeriesVO seriVO = new SeriesVO();
				seriVO.setName(this.getSeriesName(index[i]));
				seriVO.setData(this.getSeriesValue(list, index[i]));
				if(EgovStringUtil.isNotEmpty(color))seriVO.setColor(color);
				resultList.add(seriVO);
			}
		}
		return resultList;
	}
	
	private List getSeries(List<Map> list, String[] index){
		return getSeries(list, index, null, false);
	}
	private List getSeries(List<Map> list, String[] index, boolean getAreaName){
		return getSeries(list, index, null, getAreaName);
	}
	private List getSeries(List<Map> list, String[] index, String color){
		return getSeries(list, index, color, false);
	}
	
	/**
	 * 차트 값 
	 * @param list
	 * @param index
	 * @return
	 */
	private List<Double> getSeriesValue(List<Map> list, String index){
		List<Double> resultList = new ArrayList<Double>();
		for(Map vo : list){
			String tempValue = "";
			if(vo.get(index) instanceof Double){
				tempValue = String.valueOf(vo.get(index));
			}else{
				tempValue = (String)vo.get(index);
			}
			if(EgovStringUtil.isEmpty(tempValue)){
				tempValue = "0";
			}
			if(!(Arrays.toString(WaterConstants.QUALITY_CHART_NAME_INDEX).indexOf(index)>-1 && tempValue.equals("0"))){
				resultList.add(Double.parseDouble(tempValue));
			}
		}
		return resultList;
	}
	
	/**
	 * 차트 이름 값
	 * @param index
	 * @param i
	 * @return
	 */
	private String getSeriesName(String index){
		String returnString = "";
		if(Arrays.toString(WaterConstants.IOFLOW_CHART_NAME_INDEX).indexOf(index)>-1){
			for(int i=0;i<WaterConstants.IOFLOW_CHART_NAME_INDEX.length;i++){
				String cName = WaterConstants.IOFLOW_CHART_NAME_INDEX[i];
				if(cName.equals(index)){
					returnString = WaterConstants.IOFLOW_CHART_NAME[i];
					break;
				}
			}
		}else if(Arrays.toString(WaterConstants.QUALITY_CHART_NAME_INDEX).indexOf(index)>-1){
			for(int i=0;i<WaterConstants.QUALITY_CHART_NAME_INDEX.length;i++){
				String cName = WaterConstants.QUALITY_CHART_NAME_INDEX[i];
				if(cName.equals(index)){
					returnString = WaterConstants.QUALITY_CHART_NAME[i];
					break;
				}
			}
		}
		return returnString;
	}
	
	/**
	 * list 에서 목록중 마지막 Map 에서 특정 값 리턴
	 * @return
	 */
	private String getListLastMapValue(List<Map> list, String mapKey){
		return list.get(list.size()-1).get(mapKey).toString();
	}
	
	private String getJsonString(HighChartVO hchartVO) throws Exception{
		JsonConfig jc = new JsonConfig();
		JSONObject j = JSONObject.fromObject(hchartVO, jc);
		j = nullArrayRemove(j);
		log.info("##"+j.toString());
		return j.toString();
	}
	
	/**
	 * HIGHCHART 에서 배열값이 널인경우 차트가 안나오는경우가 있어 배열값이 널인경우 제거. 추가 String 이 값이 없거나 null 값이 있는경우 제거, 추가 JSONObject 가 null 경우 제거
	 * @param jsonObject
	 * @return
	 */
	private JSONObject nullArrayRemove(JSONObject jsonObject) {
		Iterator ite = jsonObject.entrySet().iterator();
		List<String> removeKeys = new ArrayList<String>();
		while (ite.hasNext()) {
			Map.Entry paraMap = (Map.Entry) ite.next();
			String strKey = (String) paraMap.getKey();
			Object objTemp = paraMap.getValue();
			if (objTemp instanceof JSONObject){
				if(((JSONObject) objTemp).isNullObject()){
					removeKeys.add(strKey);
				}else{
					jsonObject.put(strKey, nullArrayRemove((JSONObject) objTemp));
				}
			} else if (objTemp instanceof JSONArray) {
				if(((JSONArray) objTemp).size() < 1){
					removeKeys.add(strKey);
				}else{
					jsonObject.put(strKey, nullArrayRemove((JSONArray) objTemp));
				}
			} else if (objTemp instanceof String){
				String tempStr = (String)objTemp;
				if(tempStr.equals("") || tempStr.equals("null")){
					removeKeys.add(strKey);
				}
			} else if (objTemp instanceof Integer){
				if(strKey.equals("max")){
					int temp = ((Integer) objTemp).intValue();
					if(temp == 0){
						removeKeys.add(strKey);
					}
				}
			}
		}
		for(String removeKey : removeKeys){
			jsonObject.remove(removeKey);
		}
		return jsonObject;
	}
	private JSONArray nullArrayRemove(JSONArray jsonArr) {
		for (int i = 0, l = jsonArr.size(); i < l; i++) {
			Object objTemp = jsonArr.get(i);
			if (objTemp instanceof JSONObject) {
				jsonArr.element(i, nullArrayRemove((JSONObject) objTemp));
			} 
		}
		return jsonArr;
	}

}
